package com.turato.json.myjson;

/**
 * 对象解析器
 * @author turato
 */
public class ObjectParser {
    /**
     * 需要解析的json字符串
     */
    private final String json;

    /**
     * 解析进行到的位置
     */
    private int pos = 0 ;

    public ObjectParser(String json) {
        this.json = json;
    }

    /**
     * 获取当前位置
     * @return
     */
    public int getPos() {
        return pos;
    }

    /**
     * 解析 key 或者 value ,判断类型，根据类型调用不同的解析方法
     * @return
     */
    public Object nextObject(){
        if(pos >= json.length()){
            throw new JsonException("unexpected string end.");
        }
        char c = getChar();
        // 如果value为true,false,null,数字，字符串，则直接返回值；否则继续调用nextObject
        switch (c){
            //是否为 true
            case 't': case 'T':
                pos++;
                if(checkChars('r','u','e')){
                    return true;
                }
                throw new JsonException("invalid boolean value");
            //是否为 false
            case 'f': case 'F':
                pos++;
                if(checkChars('a','l','s','e')){
                    return false;
                }
                throw new JsonException("invalid boolean value");
            //是否为 null
            case 'n': case 'N':
                pos++;
                if(checkChars('u','l','l')){
                    return null;
                }
                throw new JsonException("invalid null value");
            default:
        }

        //数字
        Object number = parseNumber(c);
        if(number != null){
            return number;
        }
        //字符串开始符号
        if(c == '\"'){
           return parseString(c);
        }

        //数组开始符
        if(c == '['){
            return parseArray();
        }

        //对象开始符
        if(c == '{'){
            return parseObject();
        }
        throw new JsonException("invalid flag character : " + c);
    }

    /**
     * 检查是否已经到字符串末尾
     */
    private void checkPos(){
        if(pos >= json.length()){
            throw new JsonException("unexpected string end.");
        }
    }

    /**
     * 是否为空格
     * @param c
     * @return
     */
    public static boolean isSpace(char c){
        return c == ' ' || c == '\r' || c == '\n';
    }

    /**
     * 获取当前字符，忽略空格、换行符和回车
     * @return
     */
    private char getChar(){
        char c = json.charAt(pos);
        while(isSpace(c)){
            pos++;
            c = getCurrentChar();
        }
        return c;
    }

    /**
     * 得到当前字符，包括空格、换行符
     * @return
     */
    private char getCurrentChar(){
        checkPos();
        return json.charAt(pos);
    }

    /**
     * 解析当前字符
     * （包括空格、换行符。将指针指向下一个字符）
     */
    private char getCurrentCharNext(){
        char c = getCurrentChar();
        pos++;
        checkPos();
        return c;
    }

    /**
     * 得到当前字符，忽略空格、换行符。将指针指向下一个字符
     */
    private char getCharNext(){
        char c = getChar();
        pos++;
        checkPos();
        return c;
    }

    /**
     * 解析字符串
     * @param c
     * @return
     */
    protected String parseString(char c){
        //字符串
        pos++;
        boolean unicodeFlag = false;
        StringBuilder sb = new StringBuilder();
        //依次读取字符
        while (true){
            c = getCurrentCharNext();
            //处理转义字符
            if(c == '\\'){
                char next = getCurrentChar();
                switch (next){
                    case 'r':sb.append('\r');break;
                    case 'n':sb.append('\n');break;
                    case 'b':sb.append('\b');break;
                    case 't':sb.append('\t');break;
                    case 'u':unicodeFlag = true;sb.append("\\u");break;
                    case '\"':sb.append('\"');break;
                    default:
                        throw new JsonException("unknown escape char : " + next);
                }
                pos++;
            }else if(c == '\"'){
                //字符串结束标志
                break;
            }else{
                sb.append(c);
            }
        }
        //处理 UNICODE
        if(unicodeFlag){
            return StringUtils.asciiToNative(sb.toString());
        }
        return sb.toString();
    }

    /**
     * 解析数字
     * @param c
     * @return
     */
    protected Object parseNumber(char c){
        StringBuilder numberBuilder = new StringBuilder();
        boolean containsPoint = false;
        while (c >= '0' && c <= '9' || c == '+' || c == '-' || c == '.' ){
            if(c == '.'){
                containsPoint = true;
            }
            numberBuilder.append(c);
            pos++;
            c = getCurrentChar();
        }
        if(numberBuilder.length() > 0){
            String numberString = numberBuilder.toString();
            try{
                if(containsPoint){
                    return Double.valueOf(numberString);
                }else{
                    return Integer.valueOf(numberString);
                }
            }catch (NumberFormatException e){
                throw new JsonException("invalid number value:" + numberString,e);
            }
        }
        return null;
    }

    /**
     * 解析数组
     * @return
     */
    protected JsonArray parseArray(){
        pos++;
        checkPos();
        JsonArray jsonArray = new JsonArray();
        //是否需要用逗号分割
        boolean flag = false;
        char c = getChar();
        //数组结束符判断
        while (c != ']'){
            if(flag){
                if (c != ',') {
                    throw new JsonException("illegal json array.");
                }
                pos++;
            }
            jsonArray.add(nextObject());
            //单个元素解析完毕，解析下一个元素
            flag = true;
            if(pos >= json.length()){
                throw new JsonException("unexpected string end.");
            }
            c = getChar();
        }
        pos++;
        return jsonArray;
    }

    /**
     * 解析json对象
     * @return json对象
     */
    protected JsonObject parseObject(){
        JsonObject jsonObject = new JsonObject();
        //是否需要用逗号分割
        boolean flag = false;
        char c = getCharNext();
        //json对象结束的标志
        while (c != '}'){
            if(flag){
                if (c != ',') {
                    throw new JsonException("illegal json object separator:" + c);
                }
                pos++;
            }
            Object key = nextObject();
            if(key == null || !(key instanceof String)){
                throw new JsonException("illegal json object.key must be a string:" + key);
            }
            c = getCharNext();
            if(c != ':'){
                throw new JsonException("illegal json object pair :" + c);
            }
            Object value = nextObject();
            jsonObject.put((String) key,value);
            flag = true;
            c = getChar();
        }
        pos++;
        return jsonObject;
    }

    /**
     * 检查接下来的字符串是否为某字符串，非大小写敏感。
     * @param chars
     * @return
     */
    private boolean checkChars(char ...chars){
        for(char ch : chars){
            char c = getCurrentCharNext();
            if(Character.toLowerCase(ch) != Character.toLowerCase(c)){
                return false;
            }
        }
        return true;
    }
}
